﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using main.sdk.display.object2d;
using main.sdk.utils;
using Microsoft.Xna.Framework;

namespace main.sdk.utils.animations2D
{
    /**
     * Cria uma animação para o movimento
     * 
     * @usage
     *   // Anima a posição do objeto de From até To (Ambos são Vector2)
     *   Animation2D anim = new MoveAnimation2D(From, To, Time, Smoothness = 0, Loop = false);
     *   
     *   // Anima a posição do objeto de valor atual até To. (Vector2)
     *   Animation2D anim = new MoveAnimation2D(To, Time, Smoothness = 0, Loop = false);
     * 
     *   // Anima apenas a posição X do objeto de From até To.
     *   Animation2D anim = MoveAnimation2D.CreateX(From, To, Time, Smoothness = 0, Loop = false);     
     *   
     *   // Anima apenas a posição X do objeto do valor atual até To.
     *   Animation2D anim = MoveAnimation2D.CreateX(To, Time, Smoothness = 0, Loop = false);
     *   
     *   // Anima apenas a posição Y do objeto de From até To.
     *   Animation2D anim = MoveAnimation2D.CreateY(From, To, Time, Smoothness = 0, Loop = false);     
     *   
     *   // Anima apenas a posição Y do objeto do valor atual até To.
     *   Animation2D anim = MoveAnimation2D.CreateY(To, Time, Smoothness = 0, Loop = false);
     */
    public class MoveAnimation2D : Animation2D
    {

        #region Variables

        private Counter  m_CounterX = new Counter();
        private Counter  m_CounterY = new Counter();
        private Vector2  m_To;
        private Vector2  m_From;
        private double   m_Time;
        private int      m_Smoothness;
        private bool     m_Loop = false;
        private Object2D m_Object;

        #endregion

        #region Constructors

        /**
         * Cria a animação de movimento.
         * 
         * @param To - Destino do objeto.
         * @param Time - Tempo necessário para mover até o destino
         * @param Smoothness - Suavidade
         * @param Loop - Animação em Loop
         */
        public MoveAnimation2D(Vector2 To, double Time, int Smoothness = 0, bool Loop = false)
        {
            m_From = new Vector2(float.NaN, float.NaN);
            m_To = To;
            m_Time = Time;
            m_Loop = Loop;
            m_Smoothness = Smoothness;
        }

        /**
         * Cria a animação de movimento.
         * 
         * @param From - Posição inicial do objeto.
         * @param To - Destino do objeto.
         * @param Time - Tempo necessário para mover até o destino
         * @param Smoothness - Suavidade
         * @param Loop - Animação em Loop
         */
        public MoveAnimation2D(Vector2 From, Vector2 To, double Time, int Smoothness = 0, bool Loop = false)
        {
            m_From       = From;
            m_To         = To;
            m_Time       = Time;
            m_Loop       = Loop;
            m_Smoothness = Smoothness;
        }

        /**
         * Cria a animação de movimento apenas em X.
         * 
         * @param To - Destino X do objeto.
         * @param Time - Tempo necessário para mover até o destino
         * @param Smoothness - Suavidade
         * @param Loop - Animação em Loop
         */
        public static MoveAnimation2D CreateX(double To, double Time, int Smoothness = 0, bool Loop = false)
        {
            return new MoveAnimation2D(new Vector2((float)To, float.NaN), Time, Smoothness, Loop);
        }

        /**
         * Cria a animação de movimento apenas em X.
         * 
         * @param From - Posição X inicial do objeto.
         * @param To - Destino X do objeto.
         * @param Time - Tempo necessário para mover até o destino
         * @param Smoothness - Suavidade
         * @param Loop - Animação em Loop
         */
        public static MoveAnimation2D CreateX(double From, double To, double Time, int Smoothness = 0, bool Loop = false)
        {
            return new MoveAnimation2D(new Vector2((float)From, float.NaN), new Vector2((float)To, float.NaN), Time, Smoothness, Loop);
        }

        /**
         * Cria a animação de movimento apenas em Y.
         * 
         * @param To - Destino Y do objeto.
         * @param Time - Tempo necessário para mover até o destino
         * @param Smoothness - Suavidade
         * @param Loop - Animação em Loop
         */
        public static MoveAnimation2D CreateY(double To, double Time, int Smoothness = 0, bool Loop = false)
        {
            return new MoveAnimation2D(new Vector2(float.NaN, (float)To), Time, Smoothness, Loop);
        }

        /**
         * Cria a animação de movimento apenas em Y.
         * 
         * @param From - Posição Y inicial do objeto.
         * @param To - Destino Y do objeto.
         * @param Time - Tempo necessário para mover até o destino
         * @param Smoothness - Suavidade
         * @param Loop - Animação em Loop
         */
        public static MoveAnimation2D CreateY(double From, double To, double Time, int Smoothness = 0, bool Loop = false)
        {
            return new MoveAnimation2D(new Vector2(float.NaN, (float)From), new Vector2(float.NaN, (float)To), Time, Smoothness, Loop);
        }

        #endregion

        #region Overriden Methods

        /**
         * Verifica se a animação está ativa.
         */
        protected override bool IsActive()
        {
            /* Se animação em X está ativa */
            if (!float.IsNaN(m_To.X) && m_CounterX.Active())
                return true;
            /* Se animação em Y está ativa */
            if (!float.IsNaN(m_To.Y) && m_CounterY.Active())
                return true;
            /* Não está ativa */
            return false;
        }
        
        /**
         * Inicializa a animação
         * 
         * @param obj - O Objeto da animação.
         */
        public override void Setup(Object2D obj)
        {
            /* Salva o objeto */
            m_Object = obj;

            /* Pega os valores X e Y iniciais */
            float fromX = (float.IsNaN(m_From.X) ? obj.X : m_From.X);
            float fromY = (float.IsNaN(m_From.Y) ? obj.Y : m_From.Y);

            /* Verifica pela animação em X */
            if (!float.IsNaN(m_To.X))
                m_CounterX.Reset(fromX, m_To.X, m_Time, m_Smoothness, m_Loop);

            /* Verifica pela animação em Y */
            if (!float.IsNaN(m_To.Y))
                m_CounterY.Reset(fromY, m_To.Y, m_Time, m_Smoothness, m_Loop);
        }

        /**
         * Atualiza a animação.
         * 
         * @param Time - Tempo que passou.
         */
        public override void Update(double Time)
        {
            /* Atualiza animação em X caso ela seja válida */
            if (!float.IsNaN(m_To.X))
            {
                m_CounterX.Update(Time);
                m_Object.X = (float)m_CounterX.Value;
            }

            /* Atualiza animação em Y caso ela seja válida */
            if (!float.IsNaN(m_To.Y))
            {
                m_CounterY.Update(Time);
                m_Object.Y = (float)m_CounterY.Value;
            }
        }

        #endregion
    }
}
